<?php
/**
 * Sphink搜索引擎
 *
 * @author karl <karl.tang@aiyuangong.com>
 * @link http://www.aiyuangong.com
 */
namespace app\index\model;

require_once EXTEND_PATH.'SphinxClient.php';
class Sphinx{

    const STATE1 = 1;       // 出售中
    const STATE0 = 0;       // 下架
    const STATE10 = 10;     // 违规
    const VERIFY1 = 1;      // 审核通过
    const VERIFY0 = 0;      // 审核失败
    const VERIFY10 = 10;    // 等待审核

    //全文搜索searchd对象
    private $_sphinx_obj;

    //全文搜索index对象
    private $_sphinx_index;

    //全文搜索到的商品ID数组
    private $_indexer_ids = array();

    //全文搜索到的品牌数组
    private $_indexer_brands = array();

    //全文检索到的商品分类数组
    private $_indexer_cates = array();
    
    //最大搜索数量
    private $_sphinx_limit = 24;
    
    //建立连接超时时间（秒）
    private $_connect_timeout = 2;
    
    //搜索关键字
    private $_sphinx_keyword = '';

    //全文搜索分页结果总数
    private $_indexer_count;
    
    //全文搜索结果总数
    private $_indexer_total_count;
    
    private $host = '192.168.159.139';
    private $port = 9312;
    private $wordforms = '/usr/local/sphinx2/var/data/wordforms.txt';

    /**
     * 从全文索引库搜索关键词
     * @param unknown $condition 条件
     * @param unknown $order 排序
     * @param number $pagesize 每页显示商品数
     * @return
     */
    public function getIndexerList($condition = array(), $index='goods', $order = array(), $pagesize) {
        try {
            //全文搜索初始化
            $this->_createSphinx();

            //设置搜索内容
            $this->_setQuerySphinx($condition, $index, $order);
            
            //执行总数量搜索
            $this->_searchTotal($condition['sphinx_keyword'] = preg_replace("/([a-zA-Z0-9]{2,})/",' ${1} ',$condition['sphinx_keyword']), $index);
            
            //执行搜索
            $this->_searchSphinx($condition['sphinx_keyword'] = preg_replace("/([a-zA-Z0-9]{2,})/",' ${1} ',$condition['sphinx_keyword']), $index, $pagesize);
            return array($this->_indexer_ids, $this->_indexer_count, $this->_indexer_total_count);

        } catch (Exception $e) {
//             if (C('debug')) {
//                 showMessage($e->getMessage(),'','html','error');
//             } else {
                Shopnc\Log::record('search\index'.$e->getMessage()."\r\n".$sql,Shopnc\Log::RUN);
                return false;
//             }
        }
    }

    /**
     * 设置全文检索查询条件
     * @param unknown $condition
     * @param array $order
     */
    private function _setQuerySphinx($condition, $index, $order) {
        /* if (isset($condition['cate'])) {
            $this->_sphinx_obj->setFilter($condition['cate']['key'], $condition['cate']['value']);
        } else {
			$this->_open_face = false;
		} */
    	$this->_sphinx_obj->setFilter('goods_verify', array(self::VERIFY1));//是否审核通过
    	$this->_sphinx_obj->setFilter('goods_state', array(self::STATE1));//是否出售中
        if (isset($condition['brand_id'])) {
            $this->_sphinx_obj->setFilter('brand_id', $condition['brand_id']);
        }
        if (isset($condition['store_id'])) {
            $this->_sphinx_obj->setFilter('store_id', $condition['store_id']);
        }
        if(isset($order)){
        	foreach($order as $key => $value){
        		$this->_sphinx_obj->setSortMode($value,$key);
        	}
        }
       /*  if (isset($condition['have_gift'])) {
            $this->_sphinx_obj->setFilter('have_gift', $condition['have_gift']);
        } */
       /*  if (is_array($condition['attr_id'])) {
            foreach ($condition['attr_id'] as $attr_id) {
                $this->_sphinx_obj->setFilter('attr_id', $attr_id);
            }
        } */
        
    }

    /**
     * 创建全文搜索对象，并初始化基本参数
     * @param number $pagesize 每页显示商品数
     * @param string $appname 全文搜索INI配置文件名
     */
    private function _createSphinx() {
        $this->_sphinx_obj = new \SphinxClient();
	    $this->_sphinx_obj->setServer($this->host,$this->port);
	    //设置模式为all
	    $this->_sphinx_obj->setMatchMode(SPH_MATCH_ALL);
	    //设置模式为extended
	    $this->_sphinx_obj->setRankingMode(SPH_RANK_PROXIMITY_BM25);
    }
    
    /**
     * 执行全文总数量搜索
     */
    private function _searchTotal($phrase, $index){
    	$this->_sphinx_obj->setSelect('count(*) as total_num');
    	$result = $this->_sphinx_obj->query($phrase, $index);
    	if(isset($result['matches'])){
    		foreach ($result['matches'] as $k => $v) {
    			$this->_indexer_total_count = intval($v['attrs']['total_num']);
    			break;
    		}
    	}
    }

    /**
     * 执行全文搜索
     */
    private function _searchSphinx($phrase, $index, $pagesize){
    	if (isset($_GET['curpage']) && is_numeric($_GET['curpage']) && $_GET['curpage'] > 0) {
    		$curpage = intval($_GET['curpage']);
    		$start =  ($curpage-1) * $pagesize;
    	} else {
    		$start = 0;
    	}
        $this->_sphinx_obj->setLimits($start,$pagesize?:$this->_sphinx_limit);
    	$this->_sphinx_obj->setSelect('goods_commonid');
    	$result = $this->_sphinx_obj->query($phrase, $index);
    	if(isset($result['matches'])){
	    	foreach ($result['matches'] as $k => $v) {
	    		$goods_ids[] = $k;
	    	}
	    	$this->_indexer_ids = $goods_ids;
	    	$this->_indexer_count = count($result['matches']);
    	}
    }

    /**
     * 全文搜索
     * @return array 商品主键，搜索结果总数
     */
    public function indexerSearch($get = array(), $index, $pagesize) {
        if (!config('sphinx_open')) return array(null,0);
        $condition = array();
        $order = array();
    	switch ($index){
    		case 'goods' :
    			$index = 'goods,goods_delta';
    			list($condition,$order) = $this->_jointGoods($get);
    			break;
    		default :
    			$index = 'goods,goods_delta';
    			list($condition,$order) = $this->_jointGoods($get);
    			break;
    	}
        //取得主键等信息
        $result = $this->getIndexerList($condition,$index,$order,$pagesize);
        if ($result !== false) {
            list($indexer_ids,$indexer_count,$indexer_total_count) = $result;
            //如果全文搜索发生错误，后面会再执行数据库搜索
        } else {
            $indexer_ids = null;
            $indexer_count = 0;
        }
        return array($indexer_ids,$indexer_count,$indexer_total_count);
    }
    
    //拼接goods的搜索条件
    private function _jointGoods($get){
    	//拼接条件
    	/* if (intval($get['cate_id']) > 0) {
    		$cate_id = intval($get['cate_id']);
    	} elseif (intval($get['gc_id']) > 0) {
    		$cate_id = intval($get['gc_id']);
    	}
    	if ($cate_id) {
    		$goods_class = Model('goods_class')->getGoodsClassForCacheModel();
    		$depth = $goods_class[$cate_id]['depth'];
    		$cate_field = 'cate_'.$depth;
    		$condition['cate']['key'] = $cate_field;
    		$condition['cate']['value'] = $cate_id;
    	} */
    	if ($this->_sphinx_keyword != '') {
    		$condition['sphinx_keyword'] = $this->_sphinx_keyword;
    	}
    	/* if (intval($get['b_id']) > 0) {
    		$condition['brand_id'] = array(intval($get['b_id']));
    	} */
    	/* if (preg_match('/^[\d_]+$/',$get['a_id'])) {
    		$attr_ids = explode('_',$get['a_id']);
    		if (is_array($attr_ids)){
    			foreach ($attr_ids as $v) {
    				if (intval($v) > 0) {
    					$condition['attr_id'][] = intval($v);
    				}
    			}
    		}
    	} */
    	/* if ($get['type'] == 1) {
    		$condition['store_id'] = array(1);
    	} */
    	if (intval($get['area_id']) > 0) {
    		$condition['area_id'] = intval($get['area_id']);
    	}
    	/* if ($get['gift'] == 1) {
    		$condition['have_gift'] = 1;
    	} */
    	//拼接排序(销量,浏览量,价格)
    	$order = array();
    	$order = array('store_id' => false,'goods_commonid' => false);
    	if (in_array($get['key'],array('0','1','2','3'))) {
    		$order = array(str_replace(array('0','1','2','3'), array('goods_commonid','total_salenum','click_num','goods_price'), $get['key'])
    				=> $get['order'] == '1' ? SPH_SORT_ATTR_ASC : SPH_SORT_ATTR_DESC 
    		);
    	}
    	return array($condition, $order);
    }
    
    //获取分布式sphinx状态
    public function getStatus(){
    	$sphinx_obj = new \SphinxClient();
	    $sphinx_obj->setServer($this->host,$this->port);
	    $sphinx_obj->SetConnectTimeout($this->_connect_timeout);
    	return $sphinx_obj->Open();
    }
    
    //设置关键词
    public function setSphinxKeyword($keyword){
    	$this->_sphinx_keyword = $keyword;
    }
    
    //获取拼音转换词典全文内容
    public function getExtContents(){
    	$dictionary = $this->wordforms;
    	$contents = file_get_contents($dictionary);
    	return $contents;
    }
    
    //更新拼音转换词典全文内容
    public function updateExtContents($contents){
    	$dictionary = $this->wordforms;
    	$result = file_put_contents($dictionary, $contents.PHP_EOL, LOCK_EX);//写入内容结尾换行
    	return $result;
    }
}
